package org.jspresso.model.service;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.jspresso.framework.action.ActionBusinessException;
import org.jspresso.framework.action.ActionContextConstants;
import org.jspresso.framework.action.IAction;
import org.jspresso.framework.application.backend.BackendControllerHolder;
import org.jspresso.framework.application.backend.persistence.hibernate.HibernateBackendController;
import org.jspresso.framework.model.component.IComponent;
import org.jspresso.framework.model.component.service.AbstractComponentServiceDelegate;
import org.jspresso.framework.model.component.service.IComponentService;
import org.jspresso.framework.model.entity.IEntity;
import org.jspresso.model.ActionTestInput;
import org.jspresso.model.ActionTestOutput;
import org.jspresso.model.BackActionTest;
import org.jspresso.model.IPropertiesExludable;
import org.jspresso.model.TestEntity;
import org.jspresso.tester.utils.EntityComparator;
import org.jspresso.tester.utils.TestEntitySerializer;
import org.springframework.context.ApplicationContext;

/**
 * Generated by Jspresso Developer Studio
 */
public class BackActionTestServiceDelegate extends AbstractComponentServiceDelegate<BackActionTest> implements BackActionTestService, IComponentService {

	@SuppressWarnings("unchecked")
	public void runAssert(ApplicationContext appContext) {
		if(getComponent().getBackendBeanName() != null) {
			HibernateBackendController controller = (HibernateBackendController) BackendControllerHolder.getCurrentBackendController();
			IAction backendAction = (IAction) appContext.getBean(getComponent().getBackendBeanName());
			Map<String, Object> context = new HashMap<String,Object>();
			context.put(ActionContextConstants.BACK_CONTROLLER, controller);
			Object parameterValue = null;
			for(ActionTestInput input : getComponent().getInputs()) {

				if(input.isPrevOutputAsSource()) {
					BackActionTest prevAction = input.getBackActionTest().getPrevAction();
					if(prevAction == null) {
						throw new ActionBusinessException("No previous action could be found !");
					}
					for(ActionTestOutput prevTestOutput : prevAction.getOutputs()) {
						if((prevTestOutput.getParameterKey() == null && input.getPrevOutputParameterKey().equals(ActionContextConstants.ACTION_PARAM)) || prevTestOutput.getParameterKey().equals(input.getPrevOutputParameterKey())) {
							parameterValue = prevTestOutput.getResult().getValue();
						}
					}
				}
				else {
					switch(input.getParameterType()) {

					case ActionTestInput.PARAMETER_TYPE_REF:
						parameterValue = input.getParameterRefValue().getValue();
						break;

					case ActionTestInput.PARAMETER_TYPE_LIST:
						List<TestEntity> refValues = input.getParameterRefValues();
						parameterValue = new ArrayList<IComponent>();
						for(TestEntity parameterElement : refValues) {
							((List<IComponent>) parameterValue).add(parameterElement.getValue());
						}
						break;

					default :
						parameterValue = input.getParameterScalarValue();
						break;
					}
				}

				if(ActionTestInput.IO_TYPE_ACTION_PARAMETER.equals(input.getIoType())) {
					context.put(ActionContextConstants.ACTION_PARAM, parameterValue);
				}
				else if(ActionTestInput.IO_TYPE_CONTEXT.equals(input.getIoType())) {
					context.put(input.getParameterKey(), parameterValue);
				}
			}

			controller.execute(backendAction, context);

			for(ActionTestOutput output : getComponent().getOutputs()) {

				Object resultExpected = null;
				Object resultFound = null;

				switch(output.getParameterType()) {

				case ActionTestInput.PARAMETER_TYPE_REF:
					resultExpected = output.getParameterRefValue().getValue();
					break;

				case ActionTestInput.PARAMETER_TYPE_LIST:
					List<TestEntity> refValues = output.getParameterRefValues();
					resultExpected = new ArrayList<IComponent>();
					for(TestEntity parameterElement : refValues) {
						((List<IComponent>) resultExpected).add(parameterElement.getValue());
					}
					break;

				default :
					resultExpected = output.getParameterScalarValue();
					break;
				}

				if(ActionTestOutput.IO_TYPE_ACTION_PARAMETER.equals(output.getIoType())) {
					resultFound = context.get(ActionContextConstants.ACTION_PARAM);
				}
				else if(ActionTestOutput.IO_TYPE_ACTION_PARAMETER.equals(output.getIoType())) {
					resultFound = context.get(output.getParameterKey());
				}

				if(resultFound == null && resultExpected == null) {
					output.setLastExecutionSuccessfull(true);
				}
				else if(resultFound == null || resultExpected == null) {
					output.setLastExecutionSuccessfull(false);
				}
				else if(resultExpected instanceof IComponent && resultFound instanceof IComponent) {
					output.setLastExecutionSuccessfull(EntityComparator.isEquals((IComponent)resultFound, (IComponent)resultExpected, resultFound instanceof IPropertiesExludable ? ((IPropertiesExludable)resultFound).getExludedPropertie() : null));
				}
				else if(resultExpected instanceof List) {
					boolean matches = true;
					for(IEntity elementExpected : (ArrayList<IEntity>)resultExpected) {
						IEntity elementFound = ((List<IEntity>) resultFound).get(((ArrayList<IEntity>)resultExpected).indexOf(elementExpected));
						if(!EntityComparator.isEquals((IComponent)elementFound, (IComponent)elementExpected, elementFound instanceof IPropertiesExludable ? ((IPropertiesExludable)elementFound).getExludedPropertie() : null)) {
							matches = false;
							break;
						}
					}
					output.setLastExecutionSuccessfull(matches);
				}
				else if(resultExpected instanceof Set) {
					throw new ActionBusinessException("Set not implemented !");
				}
				else {
					output.setLastExecutionSuccessfull(resultExpected.equals(resultFound));
				}
				if(resultFound instanceof IEntity) {
					TestEntitySerializer.serializeToStore((IEntity) resultFound, null, false, true, controller);
					output.setResult(TestEntitySerializer.findTestEntity(((IEntity) resultFound).getId(), ((IEntity) resultFound).getComponentContract(), getComponent().getTestScope(), controller));
				}
			}

		}
	}

}